package com.qingyun.customview.progress.tb

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.graphics.RectF
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import androidx.annotation.ColorInt
import androidx.core.content.withStyledAttributes
import androidx.core.graphics.createBitmap
import androidx.core.graphics.toColorInt
import com.qingyun.customview.R
import java.text.DecimalFormat

class SaleProgressView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
) : View(context, attrs, defStyleAttr) {

    @ColorInt
    private var sideColor: Int = "#ff3c32".toColorInt()

    @ColorInt
    private var textColor: Int = "#ff3c32".toColorInt()
    private var sideWidth: Float = dp2px(2f)
    private var overText: String = "已售罄"
    private var nearOverText: String = "即将售罄"
    private var textSize: Float = sp2Px(16f)
    private var isNeedAnim: Boolean = true

    private var _width: Int = 0
    private var _height: Int = 0
    private var _radius: Float = 0f
    private var _bgRectF: RectF? = null

    private lateinit var sidePaint: Paint
    private lateinit var textPaint: Paint
    private lateinit var srcPaint: Paint

    private var nearOverTextWidth: Float = 0f
    private var overTextWidth: Float = 0f

    private var bgBitmap: Bitmap? = null
    private var bgSrc: Bitmap? = null
    private var fgSrc: Bitmap? = null
    private val mPorterDuffXfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)

    private var baseLineY: Float = 0f

    private var scale: Float = 0.1f
    private var totalCount = 0
    private var currentCount = 0
    private var progressCount = 0

    init {
        context.withStyledAttributes(attrs, R.styleable.SaleProgressView) {
            sideColor = getColor(R.styleable.SaleProgressView_sideColor, sideColor)
            textColor = getColor(R.styleable.SaleProgressView_textColor, textColor)
            sideWidth = getDimension(R.styleable.SaleProgressView_sideWidth, sideWidth)
            overText = getString(R.styleable.SaleProgressView_overText) ?: overText
            nearOverText = getString(R.styleable.SaleProgressView_nearOverText) ?: nearOverText
            textSize = getDimension(R.styleable.SaleProgressView_textSize, textSize)
            isNeedAnim = getBoolean(R.styleable.SaleProgressView_isNeedAnim, isNeedAnim)
        }
        initPaint()
    }

    private fun initPaint() {
        sidePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
            style = Paint.Style.STROKE
            color = sideColor
            strokeWidth = sideWidth
        }
        textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
            style = Paint.Style.FILL
            textSize = this@SaleProgressView.textSize
        }
        srcPaint = Paint(Paint.ANTI_ALIAS_FLAG)

        nearOverTextWidth = textPaint.measureText(nearOverText)
        overTextWidth = textPaint.measureText(overText)
    }


    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        _width = measuredWidth
        _height = measuredHeight
        _radius = _height / 2.0f
        if (_bgRectF == null) {
            _bgRectF = RectF(sideWidth, sideWidth, _width - sideWidth, _height - sideWidth)
        }
        if (baseLineY == 0f) {
            val fm = textPaint.fontMetrics
            baseLineY = _height / 2 + (fm.descent - fm.ascent) / 2 - fm.descent
        }
    }

    private val decimalFormat = DecimalFormat("0.00")
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (!isNeedAnim) {
            progressCount = currentCount
        }
        scale = if (totalCount == 0) {
            0.0f
        } else {
            decimalFormat.format(progressCount * 1.0f / totalCount).toFloat()
        }
        drawSide(canvas)
        drawBg(canvas)
        drawFg(canvas)
        drawText(canvas)

        if (progressCount != currentCount) {
            if (progressCount < currentCount) {
                progressCount++;
            } else {
                progressCount--;
            }
            postInvalidate();
        }
    }

    private fun drawText(canvas: Canvas) {
        val scaleText = DecimalFormat("#%").format(scale)
        val saleText = String.format("已抢%s件", progressCount)

        val scaleTextWidth = textPaint.measureText(scaleText)
        val textBitmap = createBitmap(_width, _height, Bitmap.Config.ARGB_8888)
        val textCanvas = Canvas(textBitmap)
        textPaint.color = textColor

        if (scale < 0.8f) {
            textCanvas.drawText(saleText, dp2px(10f), baseLineY, textPaint)
            textCanvas.drawText(
                scaleText,
                _width - scaleTextWidth - dp2px(10f),
                baseLineY,
                textPaint
            )
        } else if (scale < 1.0f) {
            textCanvas.drawText(
                nearOverText,
                _width / 2 - nearOverTextWidth / 2,
                baseLineY,
                textPaint
            )
            textCanvas.drawText(
                scaleText,
                _width - sideWidth - scaleTextWidth - dp2px(10f),
                baseLineY,
                textPaint
            )
        } else {
            textCanvas.drawText(
                overText,
                _width / 2 - overTextWidth / 2,
                baseLineY,
                textPaint
            )
        }
        textPaint.xfermode = mPorterDuffXfermode
        textPaint.color = Color.WHITE
        textCanvas.drawRoundRect(
            RectF(sideWidth, sideWidth, (_width - sideWidth) * scale, _height - sideWidth),
            _radius,
            _radius,
            textPaint
        )
        canvas.drawBitmap(textBitmap, 0f, 0f, null)
        textPaint.xfermode = null
    }

    private fun drawFg(canvas: Canvas) {
        if (scale == 0.0f) {
            return
        }
        val fgBitmap = createBitmap(_width, _height, Bitmap.Config.ARGB_8888)
        val fgCanvas = Canvas(fgBitmap)
        if (fgSrc == null) {
            fgSrc = BitmapFactory.decodeResource(resources, R.mipmap.fg)
        }
        fgCanvas.drawRoundRect(
            RectF(sideWidth, sideWidth, (width - sideWidth) * scale, _height - sideWidth),
            _radius,
            _radius,
            srcPaint
        )
        srcPaint.xfermode = mPorterDuffXfermode
        fgCanvas.drawBitmap(fgSrc!!, null, _bgRectF!!, srcPaint)

        canvas.drawBitmap(fgBitmap, 0f, 0f, null)
        srcPaint.xfermode = null
    }

    private fun drawBg(canvas: Canvas) {
        if (bgBitmap == null) {
            bgBitmap = createBitmap(_width, _height)
        }
        val bgCanvas = Canvas(bgBitmap!!)
        if (bgSrc == null) {
            bgSrc = BitmapFactory.decodeResource(resources, R.mipmap.bg)
        }
        bgCanvas.drawRoundRect(_bgRectF!!, _radius, _radius, srcPaint)
        srcPaint.xfermode = mPorterDuffXfermode
        bgCanvas.drawBitmap(bgSrc!!, null, _bgRectF!!, srcPaint)

        canvas.drawBitmap(bgBitmap!!, 0f, 0f, null)
        srcPaint.xfermode = null
    }

    private fun drawSide(canvas: Canvas) {
        _bgRectF ?: return
        canvas.drawRoundRect(_bgRectF!!, _radius, _radius, sidePaint)
    }

    private fun dp2px(dpValue: Float): Float {
        return TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            dpValue,
            resources.displayMetrics
        )
    }

    private fun sp2Px(spValue: Float): Float {
        val result = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_SP,
            spValue,
            resources.displayMetrics
        )
        return result
    }

    fun setTotalAndCurrentCount(totalCount: Int, currentCount: Int) {
        this.totalCount = totalCount
        var curCount = currentCount
        if (curCount > totalCount) {
            curCount = totalCount
        }
        this.currentCount = curCount
        postInvalidate()
    }
}